﻿using CN2P.ServiceModel;

namespace CN2P.Tests
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class ReviewsServiceTest : BaseServiceTest
    {
        private const string REVIEW_ITEM_TEMPLATE = @"{
      'reviewId' : 9491,
      'prodId' : '{prodId}',
      'userId' : 'user1@hotmail.com',
      'comments' : 'Great product!',
      'rating' : 5,
      'reviewDate' : '2013-03-19'
}";

        [TestMethod]
        public void productReviewWalkthoughTest()
        {
            var prod = this.CreateRandomProduct();
            var prodId = prod.ProdId;

            var userId = GetRandomUserId();

            var reviewA = this.CreateRandomProductReview(prod, userId);
            reviewA.Rating = 3;

            ProductReviewModelPagedList result = this.Service.ProductsService.GetReviews(prodId);

            Assert.AreEqual(1, result.TotalCount);
            Assert.IsTrue(result.Reviews.Any(item => item.ReviewId == reviewA.ReviewId));
            Assert.AreEqual(reviewA.ReviewId, result.Reviews[0].ReviewId);
            Assert.AreEqual(reviewA.Comments, result.Reviews[0].Comments);

            reviewA.Comments = Guid.NewGuid().ToString();
            reviewA.Rating = 3;
            this.Service.ProductsService.UpdateReview(prodId, reviewA.ReviewId, reviewA);

            result = this.Service.ProductsService.GetReviews(prodId);

            Assert.AreEqual(1, result.TotalCount);
            Assert.AreEqual(reviewA.Comments, result.Reviews[0].Comments);
            Assert.AreEqual(reviewA.Rating, result.Reviews[0].Rating);
        }

        [TestMethod]
        public void productAddReviewTest()
        {
            var prod = this.CreateRandomProduct();
            var prodId = prod.ProdId;

            var userId = GetRandomUserId();

            var reviewA = this.CreateRandomProductReview(prod, userId);
            var reviewB = this.CreateRandomProductReview(prod, userId);

            var newModel = this.Service.ProductsService.GetReviews(prodId);

            Assert.AreEqual(2, newModel.TotalCount);
            Assert.IsTrue(newModel.Reviews.Any(item => item.ReviewId == reviewA.ReviewId));
            Assert.IsTrue(newModel.Reviews.Any(item => item.ReviewId == reviewB.ReviewId));
        }

        [TestMethod]
        public void productGetReviewsOfAbsentProductTest()
        {
            var model = this.Service.ProductsService.GetReviewsOfAbsentProduct("12348");
            Assert.AreEqual(0, model.TotalCount);
        }

        [TestMethod]
        public void productAddReviewJsonTest()
        {
            var prod = this.CreateRandomProduct();
            var prodId = prod.ProdId;

            var model = this.Service.ProductsService.GetReviews(prodId);

            this.Service.ProductsService.AddReview(prodId, REVIEW_ITEM_TEMPLATE.Replace("{prodId}", prodId));
            var newModel = this.Service.ProductsService.GetReviews(prodId);

            Assert.AreEqual(model.TotalCount + 1, newModel.TotalCount);
        }

        [TestMethod]
        public void productGetProductReviewsTest()
        {
            var userId = GetRandomUserId();

            var prodA = this.CreateRandomProduct();
            var prodB = this.CreateRandomProduct();

            for (var i = 0; i < 13; i++)
            {
                this.CreateRandomProductReview(prodA, userId);
            }

            for (var i = 0; i < 25; i++)
            {
                this.CreateRandomProductReview(prodB, userId);
            }

            var prodAReviewsPage1 = this.Service.ProductsService.GetReviews(prodA.ProdId);
            var prodAReviewsPage2 = this.Service.ProductsService.GetReviews(prodA.ProdId, 1);
            var prodAReviewsPage3 = this.Service.ProductsService.GetReviews(prodA.ProdId, 2);

            var prodBReviewsPage1 = this.Service.ProductsService.GetReviews(prodB.ProdId);
            var prodBReviewsPage2 = this.Service.ProductsService.GetReviews(prodB.ProdId, 1);
            var prodBReviewsPage3 = this.Service.ProductsService.GetReviews(prodB.ProdId ,2);
            var prodBReviewsPage4 = this.Service.ProductsService.GetReviews(prodB.ProdId, 3);

            Assert.AreEqual(10, prodAReviewsPage1.Reviews.Count);
            Assert.AreEqual(3, prodAReviewsPage2.Reviews.Count);
            Assert.AreEqual(0, prodAReviewsPage3.Reviews.Count);

            Assert.AreEqual(10, prodBReviewsPage1.Reviews.Count);
            Assert.AreEqual(10, prodBReviewsPage2.Reviews.Count);
            Assert.AreEqual(5, prodBReviewsPage3.Reviews.Count);
            Assert.AreEqual(0, prodBReviewsPage4.Reviews.Count);

            var pagesA = new[] { prodAReviewsPage1, prodAReviewsPage2, prodAReviewsPage3 };
            var pagesB = new[] { prodBReviewsPage1, prodBReviewsPage2, prodBReviewsPage3, prodBReviewsPage4 };

            foreach (var pageA in pagesA)
            {
                Assert.AreEqual(13, pageA.TotalCount);
                foreach (var review in pageA.Reviews)
                {
                    Assert.AreEqual(prodA.ProdId, review.ProdId);
                }
            }

            foreach (var pageB in pagesB)
            {
                Assert.AreEqual(25, pageB.TotalCount);
                foreach (var review in pageB.Reviews)
                {
                    Assert.AreEqual(prodB.ProdId, review.ProdId);
                }
            }
        }

        [TestMethod]
        public void productUpdateReviewTest()
        {
            var prod = this.CreateRandomProduct();
            var prodId = prod.ProdId;

            var userId = GetRandomUserId();

            var reviewA = CreateRandomProductReview(prod, userId);
            var reviewB = CreateRandomProductReview(prod, userId);

            reviewA.Comments = Guid.NewGuid().ToString();
            this.Service.ProductsService.UpdateReview(prodId, reviewA.ReviewId, reviewA);

            var newModel = this.Service.ProductsService.GetReviews(prodId);

            Assert.AreEqual(2, newModel.TotalCount);

            var newA = newModel.Reviews.FirstOrDefault(item => item.ReviewId == reviewA.ReviewId);
            var newB = newModel.Reviews.FirstOrDefault(item => item.ReviewId == reviewB.ReviewId);

            Assert.AreEqual(reviewA.Comments, newA.Comments);
            Assert.AreEqual(reviewB.Comments, newB.Comments, "Second comment is untouched");
        }

        //[TestMethod]
        //public void productDeleteReviewTest()
        //{
        //    var prod = GetRandomProduct();
        //    var prodId = this.Service.ProductsService.CreateProduct(prod);

        //    var userId = GetRandomUserId();

        //    var reviewA = this.CreateRandomProductReview(prodId, userId);

        //    var reviewB = this.CreateRandomProductReview(prodId, userId);

        //    this.Service.ProductsService.RemoveReview(prodId, reviewB.ReviewId);
        //    var newModel = this.Service.ProductsService.GetReviews(prodId);
        //    Assert.AreEqual(1, newModel.TotalCount);
        //    Assert.IsTrue(newModel.Reviews.Any(item => item.ReviewId == reviewA.ReviewId));

        //    this.Service.ProductsService.RemoveReview(prodId, reviewA.ReviewId);
        //    newModel = this.Service.ProductsService.GetReviews(prodId);
        //    Assert.AreEqual(0, newModel.TotalCount);
        //}

        [TestMethod]
        public void productGetReviewByIdTest()
        {
            var prod = GetRandomProduct();
            var prodId = this.Service.ProductsService.CreateProduct(prod);
            var userId = GetRandomUserId();
            var reviews = new List<string>();
            for (var i = 0; i < 10; i++)
            {
                var review = this.CreateRandomProductReview(prodId, userId);
                reviews.Add(review.ReviewId);
            }

            var reviewId = reviews[5];
            var newReviewModel = this.Service.ProductsService.GetReview(prodId, reviewId);

            Assert.AreEqual(prodId, newReviewModel.ProdId);
            Assert.AreEqual(reviewId, newReviewModel.ReviewId);
        }
    }
}
